package com.renu.jdependencyanalyser.core;

import com.renu.jdependencyanalyser.model.ClassModel;
import com.renu.jdependencyanalyser.utils.MyProjectUtil;
import org.apache.commons.lang3.StringUtils;

import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;

public class ClassBorderGene {
    //private String extendClsSig;
    //private Set<String> implementClsSig;


    private ClassModel classModel;
    private ProjectInfo projectInfo;

    private String dirOrIndirOuterExtendClsSig;

    private Set<String> dirOrIndirOuterImplementClsSigs;

    private Set<String> dirOrIndirOuterMethodSig;

    private Set<String> dirOuterMethodSig;

    private Set<String> indirOuterMethodSig;

    private Set<String> dirOuterFields;

    private Set<String >dirDependClass;
    public ClassBorderGene(ProjectInfo projectInfo, ClassModel classModel) {
        this.projectInfo = projectInfo;
        this.classModel = classModel;
        this.dirOrIndirOuterExtendClsSig = calDirOrIndirOuterExtendClsSig();
        this.dirOrIndirOuterImplementClsSigs = calDirOrIndirOuterImplementClsSigs();
        this.dirOrIndirOuterMethodSig = calDirOrIndirOuterMethodSig();
        this.dirOuterMethodSig = calDirOuterMethodSig();
        this.indirOuterMethodSig = calIndirOuterMethodSig();
        this.dirOuterFields =  classModel.getOuterfield();
        this.dirDependClass =  classModel.getOuterDependClsSig();

    }



    public ClassModel getClassModel() {
        return classModel;
    }


    /**
     * 获取直接或者间接和outerCls相关的继承类
     * @return
     */
    private   String calDirOrIndirOuterExtendClsSig(){
        String outerExtendClsSig = classModel.getOuterExtendClsSig();
        if (!StringUtils.isEmpty(outerExtendClsSig)){
            return outerExtendClsSig;
        }
        String extendClsSig = classModel.getExtendClsSig();
        if(MyProjectUtil.isIndirOuterClass(extendClsSig,projectInfo,0)){
            return extendClsSig;
        }

        return "";
   }


    /**
     * 直接或者间接实现的外部类
     * @return
     */
     private Set<String> calDirOrIndirOuterImplementClsSigs(){
        Set<String> outerImplementClsSig = classModel.getOuterImplementClsSig();
        if (!outerImplementClsSig.isEmpty()){
            return outerImplementClsSig;
        }

        Set<String> implementClssSig = classModel.getImplementClssSig();
        HashSet<String> resSet = new HashSet<>();
        for (String s : implementClssSig) {
            if (MyProjectUtil.isIndirOuterClass(s,projectInfo,0)){
                resSet.add(s);

            }
        }
        return resSet;
    }


    /**
     * 直接或间接调用的外部方法
     * @return
     */
    private Set<String> calDirOrIndirOuterMethodSig(){
        HashSet<String> resMethodSig = new HashSet<>();
        Set<String> methodSigs = classModel.getMethodSigs();
        for (String methodSig : methodSigs) {
            if (MyProjectUtil.isIndirOuterMethod(methodSig,projectInfo,0)){
                resMethodSig.add(methodSig);
            }

        }
        return resMethodSig;

        //return resMethodSig;

    }
    private Set<String> calDirOuterMethodSig(){
        return dirOrIndirOuterMethodSig.stream().filter(methodSig -> {
            Set<String> tgtMethods = projectInfo.getMethod(methodSig).getTgtMethods();
            for (String tgtMethod : tgtMethods) {
               if (projectInfo.getBorderMethodMap().containsKey(tgtMethod)){
                   return true;
               }
            }
            return false;

        }).collect(Collectors.toSet());
    }

    private Set<String> calIndirOuterMethodSig(){
        return dirOrIndirOuterMethodSig.stream().filter(methodSig -> {
            Set<String> tgtMethods = projectInfo.getMethod(methodSig).getTgtMethods();
            for (String tgtMethod : tgtMethods) {
                if (projectInfo.getBorderMethodMap().containsKey(tgtMethod)){
                    return false;
                }
            }
            return true;
        }).collect(Collectors.toSet());
    }


    public String getDirOrIndirOuterExtendClsSig() {
        return dirOrIndirOuterExtendClsSig;
    }

    public Set<String> getDirOrIndirOuterImplementClsSigs() {
        return dirOrIndirOuterImplementClsSigs;
    }

    public Set<String> getDirOrIndirOuterMethodSig() {
        return dirOrIndirOuterMethodSig;
    }

    public Set<String> getDirOuterMethodSig() {
        return dirOuterMethodSig;
    }

    public Set<String> getIndirOuterMethodSig() {
        return indirOuterMethodSig;
    }

    public Set<String> getDirOuterFields() {
        return dirOuterFields;
    }

    public Set<String> getDirDependClass() {
        return dirDependClass;
    }
}
